package com.easydict.resolver;

import com.easydict.annotation.EasyDict;
import com.easydict.spi.DictionaryResolutionContext;
import com.easydict.spi.DictionaryResolver;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;

/**
 * 基于注解配置的枚举解析器
 * 优先于底层 DictProvider，将字段值按枚举进行翻译
 */
public class EnumDictionaryResolver implements DictionaryResolver {

    private static final int PRIORITY = 100;
    private static final String NAME = "EnumDictionaryResolver";

    @Override
    public Optional<String> resolve(DictionaryResolutionContext context) {
        EasyDict annotation = context.getAttribute("annotation", EasyDict.class);
        if (annotation == null) {
            return Optional.empty();
        }

        Class<?> enumClass = resolveEnumClass(annotation);
        if (enumClass == null || !enumClass.isEnum()) {
            return Optional.empty();
        }

        Object raw = context.getRawValue();
        if (raw == null) {
            return Optional.empty();
        }

        try {
            Method codeGetter = tryGetMethod(enumClass, annotation.enumCodeMethod());
            Method labelGetter = tryGetMethod(enumClass, annotation.enumLabelMethod());

            Object[] constants = enumClass.getEnumConstants();

            // 字段本身就是该枚举
            if (enumClass.isInstance(raw)) {
                Object label = (labelGetter != null) ? labelGetter.invoke(raw) : raw.toString();
                return Optional.ofNullable(label == null ? null : String.valueOf(label));
            }

            // 字段是“代码”，用 codeMethod 匹配枚举常量
            String rawStr = String.valueOf(raw);
            if (codeGetter != null) {
                return Arrays.stream(constants)
                        .filter(e -> {
                            try {
                                Object code = codeGetter.invoke(e);
                                return code != null && rawStr.equals(String.valueOf(code));
                            } catch (Exception ignore) {
                                return false;
                            }
                        })
                        .findFirst()
                        .map(e -> {
                            try {
                                Object label = (labelGetter != null) ? labelGetter.invoke(e) : e.toString();
                                return label == null ? null : String.valueOf(label);
                            } catch (Exception ex) {
                                return null;
                            }
                        });
            }

            // 兜底：按 name()/toString 匹配
            return Arrays.stream(constants)
                    .filter(e -> rawStr.equals(String.valueOf(e)))
                    .findFirst()
                    .map(Object::toString);

        } catch (Exception e) {
            return Optional.empty();
        }
    }

    @Override
    public int getPriority() {
        return PRIORITY;
    }

    @Override
    public boolean supports(DictionaryResolutionContext context) {
        EasyDict annotation = context.getAttribute("annotation", EasyDict.class);
        Class<?> enumClass = (annotation == null) ? null : resolveEnumClass(annotation);
        return enumClass != null && enumClass.isEnum();
    }

    @Override
    public String getName() {
        return NAME;
    }

    private Class<?> resolveEnumClass(EasyDict anno) {
        if (anno.enumClass() != null && anno.enumClass() != Void.class) {
            return anno.enumClass();
        }
        String name = anno.enumClassName();
        if (name == null || name.trim().isEmpty()) {
            return null;
        }
        try {
            return Class.forName(name.trim());
        } catch (ClassNotFoundException e) {
            try {
                ClassLoader cl = Thread.currentThread().getContextClassLoader();
                if (cl == null) {
                    cl = EnumDictionaryResolver.class.getClassLoader();
                }
                return Class.forName(name.trim(), false, cl);
            } catch (ClassNotFoundException ex) {
                return null;
            }
        }
    }

    private Method tryGetMethod(Class<?> type, String name) {
        try {
            return type.getMethod(name);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }
}


